package com.xcity.game.activity2.singlerecharge;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.xcity.Server;
import com.xcity.db.entity.Activity;
import com.xcity.db.entity.Player;
import com.xcity.game.activity2.ActivityImpl;
import com.xcity.game.activity2.singlerecharge.model.ActivityData;
import com.xcity.game.activity2.singlerecharge.model.SingleRechargeData;
import com.xcity.game.activity2.singlerecharge.model.SingleRechargeData.Record;
import com.xcity.game.activity2.singlerecharge.template.SingleRechargeActivityTemplate;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.event.GameEvents;
import com.xcity.game.item.ItemInfo;
import com.xcity.game.item.listener.DefaultBagListener;
import com.xcity.game.player.PlayerService;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.push.msg.ActivityStatePush;
import com.xcity.pomelo.request.ActivitySingleRechargeInfoRequest;
import com.xcity.pomelo.request.ActivitySingleRechargeRewardRequest;
import com.xcity.pomelo.response.ActivitySingleRechargeInfoResponse;
import com.xcity.pomelo.response.ActivitySingleRechargeRewardResponse;
import com.xcity.pomelo.response.HintResponse;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.ServiceException;
import naga.x.util.TimeUtils;

/**
 * 单笔充值活动
 * @author yang.li
 *
 */
@OPHandler
public class SingleRechargeActivity extends ActivityImpl implements EventListener {

	private List<SingleRechargeActivityTemplate> templates;
	private ActivityData data;
	
	private String rechargeTimeText, rewardTimeText; // for client
	
	public SingleRechargeActivity(Activity entity) {
		super(entity);
	}

	@Override
	public String getId() {
		return getClass().getName();
	}

	@Override
	public void init() {
		templates = App.getApp().getServiceManager().get(TemplateService.class).getTemplatesList(SingleRechargeActivityTemplate.class);
		data = entity.getDataObj(ActivityData.class);
		rechargeTimeText = TimeUtils.format("yyyy年MM月dd日", entity.getBeginTime()) + '~' + TimeUtils.format("yyyy年MM月dd日", data.rechargeEndTime);
		rewardTimeText = TimeUtils.format("yyyy年MM月dd日", entity.getBeginTime()) + '~' + TimeUtils.format("yyyy年MM月dd日", entity.getEndTime());
	}

	@Override
	public void save() {
	}

	@Override
	public void startup() throws ServiceException {
		App.getApp().getEventManager().register(this);
		Server.broadcast(new ActivityStatePush(entity.getUniqueId(), Activity.STATE_OPENED));
	}

	@Override
	public void shutdown() throws ServiceException {
		App.getApp().getEventManager().unRegister(this);
		clearOnlines();
		Server.broadcast(new ActivityStatePush(entity.getUniqueId(), Activity.STATE_CLOSED));
	}

	@Override
	public boolean update() {
		return true;
	}

	@Override
	public void setDirty() {
		ActivityData preData = data;
		init();
		if (preData.serial == data.serial) {
			return;
		}
		clearOnlines();
	}
	
	private void clearOnlines() {
		Collection<Player> players = App.getApp().getServiceManager().get(PlayerService.class).getOnlinePlayers();
		for (Player player : players) {
			SingleRechargeActivityUtils.clear(player, data);
		}
	}

	@Override
	public int[] getEventTypes() {
		return new int[] { GameEvents.EVENT_PLAYER_LOADED, GameEvents.EVENT_RECHARGE };
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.getType()) {
			case GameEvents.EVENT_PLAYER_LOADED:
				firePlayerLoaded(event.getParameter(0));
				break;
			case GameEvents.EVENT_RECHARGE:
				fireRecharged(event.getParameter(0), event.getParameter(1));
				break;
		}
	}
	
	private void firePlayerLoaded(Player player) {
		SingleRechargeActivityUtils.clear(player, data);
		player.send(new ActivityStatePush(entity.getUniqueId(), Activity.STATE_OPENED));
	}
	
	private void fireRecharged(Player player, int money) {
		if (!rechargeable()) {
			return;
		}
		SingleRechargeData srd = SingleRechargeActivityUtils.get(player, data);
		List<SingleRechargeActivityTemplate> list = templates;
		for (int i = list.size() - 1; i >= 0; i--) {
			SingleRechargeActivityTemplate template = list.get(i);
			if (money >= template.getMoney()) {
				Record record = srd.lookupOrCreate(template.getMoney());
				if (record.getReceivedNum() + record.getAvailableNum() < template.getNumLimit()) {
					record.fireRecharged();
					LOG.info("[SINGLE RECHARGE]ID[{}]MONEY1[{}]MONEY2[{}]", player.getId(), template.getMoney(), money);
					break;
				}
			}
		}
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_SINGLE_RECHARGE_INFO)
	protected void requestInfo(Session session, ActivitySingleRechargeInfoRequest req) {
		Player player = session.getClient();
		SingleRechargeData data = SingleRechargeActivityUtils.get(player);
		ActivitySingleRechargeInfoResponse res = new ActivitySingleRechargeInfoResponse(req.getSerial());
		res.activityTime = rechargeTimeText;
		res.rewardTime = rewardTimeText;
		List<SingleRechargeActivityTemplate> list = templates;
		int size = list.size();
		res.entrys = new ArrayList<ActivitySingleRechargeInfoResponse.Entry>(size);
		for (int i = 0; i < size; i++) {
			SingleRechargeActivityTemplate template = list.get(i);
			Record record = data != null ? data.lookup(template.getMoney()) : null; // 该项充值记录
			ActivitySingleRechargeInfoResponse.Entry entry = new ActivitySingleRechargeInfoResponse.Entry();
			entry.id = i; // index
			entry.money = template.getMoney();
			entry.numLimit = record != null ? template.getNumLimit() - record.getReceivedNum() : template.getNumLimit();
			if (entry.numLimit < 0) {
				entry.numLimit = 0;
			}
			if (record != null) {
				if (record.getReceivedNum() >= template.getNumLimit()) {
					// 领取次数已达上限
					entry.state = 2;
				} else if (record.getAvailableNum() > 0) {
					// 还有剩余领取次数
					entry.state = 1;
				} // else 未充值，不能领取
			}
			entry.items = template.getItemsWrapped();
			res.entrys.add(entry);
		}
		
		session.send(res);
	}
	
	@PomeloOP(PomeloRoute.ACTIVITY_SINGLE_RECHARGE_REWARD)
	protected void requestReward(Session session, ActivitySingleRechargeRewardRequest req) {
		if (!isActive()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ACTIVITY_ENDED));
			return;
		}
		List<SingleRechargeActivityTemplate> list = templates;
		if (req.id < 0 || req.id >= list.size()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CAN_NOT_GET_REWARD));
			return;
		}
		Player player = session.getClient();
		SingleRechargeData data = SingleRechargeActivityUtils.get(player);
		if (data == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CAN_NOT_GET_REWARD));
			return;
		}
		SingleRechargeActivityTemplate template = list.get(req.id);
		Record record = data.lookup(template.getMoney());
		if (record == null || record.getAvailableNum() <= 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CAN_NOT_GET_REWARD));
			return;
		}
		ItemInfo[] items = template.getItemsWrapped();
		if (player.getBag().getFreeSize() < items.length) {
			session.send(new HintResponse(req.getSerial(), MessageConst.BAG_FULL));
			return;
		}
		record.fireReceived();
		DefaultBagListener lsr = new DefaultBagListener();
		for (ItemInfo item : items) {
			int n = lsr.size();
			player.getBag().addItemWithoutException(item.getTemplate(), item.getCount(), Cause.SINGLE_RECHARGE, lsr);
			if (n == lsr.size()) { // didn't add to the sync packet?
				lsr.itemAdded(item.getTemplate(), item.getCount());
			}
		}
		ActivitySingleRechargeRewardResponse res = new ActivitySingleRechargeRewardResponse(req.getSerial());
		res.id = req.id;
		res.numLimit = template.getNumLimit() - record.getReceivedNum();
		if (res.numLimit < 0) res.numLimit = 0;
		res.state = (byte) (record.getReceivedNum() >= template.getNumLimit() ? 2 : (record.getAvailableNum() > 0 ? 1 : 0));
		session.send(res);
		
		session.send(lsr.getPacket());
		LOG.info("[SINGLE RECHARGE REWARD]ID[{}]MONEY[{}]NUM[{}]", player.getId(), template.getMoney(), record.getReceivedNum());
	}
	
	private boolean rechargeable() {
		long now = TimeUpdater.getInstance().now();
		return now >= entity.getBeginTime().getTime() && now <= data.rechargeEndTime;
	}

}
